package lv.ante.xwiki.cli;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * This is the main class to run various system commands. 
 * 
 * @author kap
 */
public class CommandLineExecutor {

	protected ResponseStreamHandler outputStreamHandler;

	protected ResponseStreamHandler errorStreamHandler;
	
	protected Process proc; 
	
	protected String[] commandLine;
	
	public CommandLineExecutor(ResponseStreamHandler outputHandler,
			ResponseStreamHandler errorHandler) {
		super();
		outputStreamHandler = outputHandler;
		errorStreamHandler = errorHandler;
	}

	public void execute(String[] commandLine) throws IOException {
		this.commandLine = commandLine;
		proc = Runtime.getRuntime().exec(commandLine);

		Thread procInputHandler = new Thread() {
			public void run() {
				InputStream in = proc.getInputStream();

				try {
					int nextChar;
					while ((nextChar = in.read()) != -1) {
						if (outputStreamHandler != null) {
							outputStreamHandler.handle(nextChar);
						}
					}
					if (outputStreamHandler != null) {
					    outputStreamHandler.handle('\n');
					}
					in.close();
				} catch (IOException e) {
					System.err.println("STDOUT Error " + e);
					e.printStackTrace(System.err);
					// assume we are done at this point
				}

			}
		};

		Thread procErrorHandler = new Thread() {
			public void run() {
				InputStream in = proc.getErrorStream();

				try {
					int nextChar;
					while ((nextChar = in.read()) != -1) {
						if (errorStreamHandler != null) {
							errorStreamHandler.handle(nextChar);
						}
					}
					in.close();
				} catch (IOException e) {
					System.err.println("STDERR Error " + e);
					e.printStackTrace(System.err);
					
					// assume we are done at this point
				}
			}
		};

		procInputHandler.start();
		procErrorHandler.start();
	}

	public int close() throws IOException {
		try {
			proc.waitFor();
		} catch (InterruptedException e1) {
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < commandLine.length; i++) {
				sb.append(commandLine[i]);
				if (i < commandLine.length -1) {
					sb.append(' ');
				}
			}
			throw new IOException("Process interupted while waiting for completion '"
					+ sb.toString() + "' to complete");
		}
		int exitVal = proc.exitValue();

		return exitVal;
	}
	
	public OutputStream getOutputStream() {
		return proc.getOutputStream();
	}
}
